package com.webrtc.demo

import com.webrtc.demo.call.*
import com.webrtc.demo.util.Utils
import com.webrtc.demo.util.logD
import org.webrtc.CapturerObserver
import org.webrtc.IceCandidate
import org.webrtc.SessionDescription
import org.webrtc.SurfaceViewRenderer

class MultiCallHelper(
    val localUid: String,
    private val remoteUids: List<String>,
    roomId: String?,
    val callerUid: String?,
    private val listener: MutiCallUserListener
) {
    val conversationId: String
    val isCaller: Boolean

    val otherMediaConnections: MutableMap<String, MediaConnection> = mutableMapOf()
    private val peers: MutableList<String> = mutableListOf() // 已加入会话的用户（除我以外）

    // 接收到广播或者收到ack，执行本地添加
    private fun addUser(uid: String, sendOffer: Boolean) {
        val firstAdd = peers.isEmpty()

        if (!peers.contains(uid)) {

            peers.add(uid)
            log("新加入用户 $uid")

            if (firstAdd) {

                otherMediaConnections[uid] =
                    ConnectionManager.getMedia(uid).also { it.cId = conversationId }
                otherMediaConnections[uid]?.setSurfaceViewRenderer(
                    listener.onBindSurface(localUid),// 自己
                    listener.onBindSurface(uid)// 第一个用户
                )

                listener.onLocalCapturerObserver(otherMediaConnections[uid]?.getCapturerObserver()!!)
            } else {

                val firstMediaConnection = otherMediaConnections.values.first()
                otherMediaConnections[uid] =
                    ConnectionManager.getMedia(
                        uid,
                        firstMediaConnection.localVideoTrack,
                        firstMediaConnection.localAudioTrack
                    ).also { it.cId = conversationId }

                otherMediaConnections[uid]?.setSurfaceViewRenderer(
                    null,
                    listener.onBindSurface(uid)
                )
            }
        }

        if (sendOffer) {
            otherMediaConnections[uid]?.connect()
        }
    }

    private fun removeUser(uid: String) {
        peers.remove(uid)

        log("移除用户 $uid")

        otherMediaConnections.remove(uid)?.let {
            it.close() // 数据关闭
            it.pRemoteSurfaceView?.let { surface ->
                listener.onUnBindSurface(surface) // UI移除
            }
        }
    }

    interface MutiCallUserListener {
        fun onLocalCapturerObserver(observer: CapturerObserver)
        fun onBindSurface(uid: String): SurfaceViewRenderer
        fun onUnBindSurface(surface: SurfaceViewRenderer)
        // 是发起者再处理此消息
        fun onUserDeny(uid: String)
    }

    private fun uidsAppend(uids: List<String>, vararg removes: String): String {
        val sb = StringBuilder()
        uids.forEach {
            if (!removes.contains(it))
                sb.append(it).append(',')
        }
        return sb.toString()
    }

    private fun log(msg: String) = logD(TAG, "conversationId:${this.conversationId}，$msg")

    companion object {
        const val TAG = "MultiCallHelper"
    }

    private val signalEventListener: OnSignalEventListener

    init {
        this.conversationId = roomId ?: genCId()
        this.isCaller = roomId == null

        if (isCaller) {// 我如果是发起者，remoteUids不为空，先添加空view
            remoteUids.forEach { uid ->
                addUser(uid, sendOffer = false)// 收到ack再发offer
            }
        } else {// 接听者，准备接听发起者的offer
            addUser(callerUid!!, sendOffer = false)
        }

        signalEventListener = object : OnSignalEventListener {
            override fun onNegotiate(uid: String, type: Negotiate): Boolean {
                return false
            }

            override fun onRoomNegotiate(
                uid: String,
                roomid: String,
                type: RoomNegotiate
            ): Boolean {
                return if (roomid == this@MultiCallHelper.conversationId) {

                    when (type) {
                        RoomNegotiate.ROOM_CALL -> {
                            return false
                        }
                        RoomNegotiate.ROOM_ACK -> { // 能收到ack说明我是请求者
                            // 对方接收多人视频通话请求，广播给其它参与者，除了我和对方以外的人

                            log("$uid 返回了Ack")

                            if (isCaller && peers.isNotEmpty())
                                RTCSignalClient.sendRoomBroadcast(
                                    peers.filter { it != uid },
                                    this@MultiCallHelper.conversationId,
                                    uid,
                                    RoomBroadcastType.JOIN
                                ) {
                                    log("新人加入广播成功")
                                }
                            // 本地添加该用户
                            addUser(uid, sendOffer = true)
                        }
                        RoomNegotiate.ROOM_DENY -> {
                            // 收到拒绝消息，说明我是发起人，可能要移除该用户
                            listener.onUserDeny(uid)
                            removeUser(uid)
                        }
//                        RoomNegotiate.ROOM_SHUT -> {
//                            log("$uid 退出了会话")
//                            removeUser(uid)
//                            // 发起人收到有人退出，广播此人退出的消息???
//                            if (isCaller && peers.isNotEmpty())
//                                RTCSignalClient.sendRoomBroadcast(
//                                    peers,
//                                    this@MultiCallHelper.conversationId,
//                                    uid,
//                                    RoomBroadcastType.EXIT
//                                ) {
//                                    log("$uid 离开的广播 发送成功")
//                                }
//                        }
                    }

                    true
                } else false
            }

            override fun onRoomBroadcast(
                uid: String,
                newid: String,
                roomid: String,
                roomBroadcastType: RoomBroadcastType
            ): Boolean {
                return if (roomid == conversationId) {

                    when (roomBroadcastType) {
                        RoomBroadcastType.JOIN -> {
                            addUser(newid, true)
                        }
                        RoomBroadcastType.EXIT -> {
                            removeUser(uid)// 谁发送的谁离开
                        }
                    }

                    true
                } else false
            }

            override fun onOffer(
                uid: String,
                sdp: String,
                mediaType: MediaType,
                roomid: String?
            ): Boolean {
                // 接收之前的人
                return if (roomid == conversationId) {
                    // 被动接收的offer，针对我加入时，之前的人会主动加我
                    if (!otherMediaConnections.containsKey(uid))
                        addUser(uid, sendOffer = false)

                    otherMediaConnections[uid]?.onOffer(
                        SessionDescription(
                            SessionDescription.Type.OFFER,
                            sdp
                        )
                    )

                    log("收到 $uid 的offer")

                    true
                } else false
            }

            override fun onAnswer(
                uid: String,
                sdp: String,
                mediaType: MediaType,
                roomid: String?
            ): Boolean {
                return if (roomid == conversationId) {
                    otherMediaConnections[uid]?.let {
                        it.onAnswer(SessionDescription(SessionDescription.Type.ANSWER, sdp))

                        log("收到$uid 的answer")

                        true
                    } ?: false
                } else false
            }

            override fun onCandidate(
                uid: String,
                ice: IceCandidate,
                mediaType: MediaType,
                roomid: String?
            ): Boolean {
                return if (roomid == conversationId) {
                    otherMediaConnections[uid]?.let {
                        it.onIceCandidate(ice, true)
                        true
                    } ?: false
                } else false
            }
        }
        // 处理连接请求
        RTCSignalClient.addOnSignalEventListener(signalEventListener)

        // 启动
        if (isCaller) {
            RTCSignalClient.sendRoomNegotiate(
                uidsAppend(remoteUids),
                this.conversationId,
                RoomNegotiate.ROOM_CALL
            ) {
                log("发送多人视频Call信号成功")
            }
        } else {// 响应
            RTCSignalClient.sendRoomNegotiate(
                callerUid!!,
                this.conversationId,
                RoomNegotiate.ROOM_ACK
            ) {
                log("发送 多人视频ACK 信号成功")
            }
        }
    }

    private fun genCId(): String { // 我的id+当前毫秒时间+其余用户id 对此字符串计算md5
        val sb = StringBuilder(localUid)
        sb.append(System.currentTimeMillis())
        remoteUids.forEach { sb.append(it) }
        return Utils.md5Decode32(sb.toString())!!
    }

    fun leave() {
//        if (callerUid != null) {
//            RTCSignalClient.sendRoomNegotiate(
//                callerUid,
//                this.conversationId,
//                RoomNegotiate.ROOM_SHUT
//            ) {
//                log("自己离开信令 已发送给发起人")
//            }
//        }
        RTCSignalClient.sendRoomBroadcast(
            peers,
            this.conversationId,
            localUid,
            roomBroadcastType = RoomBroadcastType.EXIT
        ) {
            log("自己离开广播已发送")
        }
    }

    fun close() {
        RTCSignalClient.removeOnSignalEventListener(signalEventListener)

        otherMediaConnections.values.forEach {
            it.close()
        }
    }
}